package city.spring.modules.work.service.impl;

import city.spring.modules.work.action.WorkPlanCalculationUtils;
import city.spring.modules.work.action.model.AbstractPlanShift;
import city.spring.modules.work.action.model.AbstractPlanUser;
import city.spring.modules.work.entity.WorkScheduleEntity;
import city.spring.modules.work.entity.WorkScheduleItemEntity;
import city.spring.modules.work.entity.WorkScheduleShiftEntity;
import city.spring.modules.work.service.GenerateWorkScheduleService;
import city.spring.modules.work.service.WorkPlanService;
import city.spring.modules.work.service.WorkScheduleItemService;
import city.spring.modules.work.service.WorkScheduleShiftService;
import city.spring.modules.work.vo.WorkPlanShiftVO;
import city.spring.modules.work.vo.WorkPlanUserVO;
import city.spring.modules.work.vo.WorkPlanVO;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 排班表生成
 *
 * @author HouKunLin
 * @date 2020/6/8 0008 16:18
 */
@Transactional(rollbackFor = Exception.class)
@Service
public class GenerateWorkScheduleServiceImpl implements GenerateWorkScheduleService {
    private final WorkPlanService planService;
    private final WorkScheduleItemService scheduleItemService;
    private final WorkScheduleShiftService scheduleShiftService;

    public GenerateWorkScheduleServiceImpl(WorkPlanService planService, WorkScheduleItemService scheduleItemService, WorkScheduleShiftService scheduleShiftService) {
        this.planService = planService;
        this.scheduleItemService = scheduleItemService;
        this.scheduleShiftService = scheduleShiftService;
    }

    @Async
    @Override
    public void generateSchedule(WorkScheduleEntity scheduleEntity) {
        WorkPlanVO workPlan = planService.getWorkPlan(scheduleEntity.getWorkPlanId());
        // 转换成排班所需要的班次对象列表
        List<AbstractPlanShift<WorkPlanShiftVO>> planShifts = workPlan.getShifts()
                .stream()
                .map(WorkPlanShiftVO::toPlanShift)
                .collect(Collectors.toList());
        // 转换成排班所需要的用户对象列表
        List<AbstractPlanUser<WorkPlanUserVO>> planUsers = workPlan.getUsers()
                .stream()
                .map(WorkPlanUserVO::toPlanUser)
                .collect(Collectors.toList());
        WorkPlanCalculationUtils<WorkPlanShiftVO, WorkPlanUserVO> utils = new WorkPlanCalculationUtils<>(
                scheduleEntity.getStartDate(), scheduleEntity.getEndDate(),
                planShifts, planUsers,
                workPlan.getWorkingDaySet());
        // 执行排班前的参数自动配置（计算每个班次的人数等）
        utils.autoConfig();
        // 执行排班运算
        utils.run();

        Map<AbstractPlanShift<WorkPlanShiftVO>, WorkScheduleShiftEntity> map = new HashMap<>();
        // 把排班方案的班次列表转换为排班结果的班次列表对象，保存这个排版结果的班次列表信息，对班次做冗余
        List<WorkScheduleShiftEntity> scheduleShiftEntities = planShifts.stream().map(item -> {
            WorkPlanShiftVO planShiftVO = item.getObject();
            WorkScheduleShiftEntity shiftEntity = new WorkScheduleShiftEntity();
            shiftEntity.setWorkScheduleId(scheduleEntity.getId());
            shiftEntity.setTitle(planShiftVO.getTitle());
            shiftEntity.setStartTime(planShiftVO.getStartTime());
            shiftEntity.setEndTime(planShiftVO.getEndTime());

            map.put(item, shiftEntity);
            return shiftEntity;
        }).collect(Collectors.toList());
        scheduleShiftService.saveBatch(scheduleShiftEntities);

        // 存放所有的排班结果记录（某天某个班次某个人在上班）
        List<WorkScheduleItemEntity> scheduleItemEntities = new ArrayList<>();
        // 拿到所有的结果
        utils.resultForEach((date, shift, user) -> {
            WorkScheduleItemEntity scheduleItemEntity = new WorkScheduleItemEntity();
            scheduleItemEntity.setDate(date);
            // 设置关联用户ID
            scheduleItemEntity.setUserId(user.getObject().getUserId());
            // 设置关联排班结果ID
            scheduleItemEntity.setWorkScheduleId(scheduleEntity.getId());
            // 设置关联排班结果的班次ID
            scheduleItemEntity.setWorkScheduleShiftId(map.get(shift).getId());
            scheduleItemEntity.setIsEnabled(true);
            scheduleItemEntity.setStatus(0);
            scheduleItemEntities.add(scheduleItemEntity);
        });
        // 保存排班结果记录信息
        scheduleItemService.saveBatch(scheduleItemEntities);
    }
}
